﻿
#include <map>
#include <iomanip>
#include <algorithm>
#include <shared_mutex>
#include "managestu.h"
#include "util/FileUtils.h"
#include "context/UserContext.h"
#include "entity/Graduate.h"
#include "concurrent/ThreadPool.h"
#include "exception/CustomException.h"
#include "entity/Undergraduate.h"

using namespace gao;
shared_mutex ManageStu::m_rwMutex;
ManageStu* ManageStu::m_instance = nullptr;
mutex ManageStu::m_mtx;

ManageStu* ManageStu::getInstance() {
    if (m_instance==nullptr) {
        unique_lock<mutex> lock(m_mtx);
        if (m_instance == nullptr) {
            m_instance = new ManageStu();
        }
    }
    return m_instance;
}


void ManageStu::addStudent() {
    cout<<"请选择学生类型:"<<endl;
    cout<<"1.本科生 2.研究生"<<endl;
    int type;
    checkInput(type);
    cout<<"请输入学生信息:"<<endl;
    unique_ptr<Student> student;
    if (type==1) {
        student=make_unique<Undergraduate>();
    }else {
        student=make_unique<Graduate>();
    }

    checkInput(*student);
    if (!isExist(student->getId())) {
        try {
            m_set.insert(student->getId());
            m_arr.emplace_back(std::move(student));
            cout<<"Add student successfully!"<<endl;
        }catch (CustomException& e) {
            ThreadPool *threadPool = ThreadPool::getInstance();
            auto current_user = UserContext::getCurrentUser();
            threadPool->addTask([e,current_user](){FileUtils::logAccess(e.what(),false,current_user);});
            m_set.erase(student->getId());
        }

    }else
        cout<<"This student already exists!"<<endl;
}

void ManageStu::print() {
    notifyStus();
}

void ManageStu::delStudent(int id) {
    auto it = findStudent(id);
    if (it==m_arr.end()) {
        return;
    }
    cout<<"确认要删除嘛?"<<endl;
    cout<<"1.确认";
    cout<<"2.取消"<<endl;
    int choice;
    cin>>choice;
    if (choice==1) {
        m_arr.erase(it);
        m_set.erase(id);
        cout<<"删除成功"<<endl;
    }else {
        cout<<"取消删除"<<endl;
    }
    system("pause");
}


vector<unique_ptr<Student>>::const_iterator ManageStu::findStudent(int id) const {
    if (!isExist(id)) {
        cout<<"不存在该学生"<<endl;
        return m_arr.end();
    }
    return find_if(m_arr.begin(), m_arr.end(), [id](const auto& student) {
        return student->getId() == id;
    });
}


void ManageStu::updateStudent(int id) {
    auto it = findStudent(id);
    if (it==m_arr.end()) {
        return;
    }
    m_set.erase(it->get()->getId());
    cout<<"Input student Info which you will change:"<<endl;
    cin>>*(*it);
    m_set.insert(it->get()->getId());
    cout<<"更新成功!"<<endl;
    cout<<"更新后的信息: ";
    (*it)->reflect();
    system("pause");
}

void ManageStu::queryStudent() {
    int type;
    cout<<"请选择查询方式:"<<endl;
    cout<<"1.id查询"<<endl;
    cout<<"2.name查询"<<endl;
    cin>>type;
    vector<unique_ptr<Student>>::const_iterator it=m_arr.end();
    if (type==2) {
        string name;
        cout<<"请输入要查询的学生名称:"<<endl;
        cin>>name;
        it = find_if(m_arr.begin(),m_arr.end(),
            [&name](const auto& student){return student->getName() == name;});
    }
    else if (type==1) {
        int id;
        cout<<"请输入要查询的学生id:"<<endl;
        checkInput(id);
        it = findStudent(id);
    }else {
        cout<<"Invalid input!"<<endl;
        return;
    }

    if (it!=m_arr.end()) {
        (*it)->reflect();
    }else {
        cout<<"No such student"<<endl;
    }
    system("pause");
}

void ManageStu::notifyStus() {
    cout<<"=============================================="<<endl;
    std::sort(m_arr.begin(), m_arr.end(), [](const unique_ptr<Student>& a, const unique_ptr<Student>& b) {
        return a->getName() < b->getName();
    });
    for_each(m_arr.begin(),m_arr.end(),[](const unique_ptr<Student> &p){p->reflect();});
    cout<<"=============================================="<<endl;
    system("pause");
}

void ManageStu::clear(bool isConfirm)
{
    if (!isConfirm) {
        m_set.clear();
        m_arr.clear();
        cout<<"本地内存数据清空成功"<<endl;
        return;
    }
    int confirm;
    cout<<"确认清空所有学生信息吗?"<<endl;
    cout<<"1.确认 2.取消"<<endl;
    checkInput(confirm);
    if (confirm==1) {
        m_set.clear();
        m_arr.clear();
    }
}

bool ManageStu::isExist(int key) const {
    return m_set.contains(key);
}

void ManageStu::saveAllStus() {
    FileUtils::saveAllStus(m_arr);
    cout<<"磁盘数据保存成功"<<endl;
}

void ManageStu::loadAllStus() {
    FileUtils::loadAllStus(m_arr,m_set);
}


void ManageStu::menu() {
    //设置用户上下文,便于后续操作和记录日志
    UserContext::setCurrentUser();
    enum Rank {
        ADD = 1,  // 显式赋值为1
        DELETE,
        UPDATE,
        FIND,
        PRINT,
        CLEAR,
        EXIT,
    };
    // map映射,便于构建操作日志
    map<int,string> rankMap = {
        {ADD,"add"},
        {DELETE,"delete"},
        {UPDATE,"update"},
        {FIND,"find"},
        {PRINT,"print"},
        {CLEAR,"clear"},
        {EXIT,"exit"},};
    {
        //加读锁
        shared_lock<shared_mutex> lock(m_rwMutex);
        loadAllStus();
    }

    ThreadPool* threadPool = ThreadPool::getInstance();
    do{
        //打印菜单
        printMenu();
        int select=0;
        cout<<"pelease choose:"<<endl;
        //输入检查是否合法
        checkInput(select);

        //输入在范围内时，进行日志记录
        if (rankMap.count(select)==1) {
            auto current_user = UserContext::getCurrentUser();
            threadPool->addTask([rankMap,select,&current_user]()
                {FileUtils::logAccess(rankMap.find(select)->second,true,current_user);});
        }
        switch (select) {

            case ADD: {
                while (true) {
                    addStudent();
                    cout<<"如果继续添加,请按1,退出添加按0"<<endl;
                    checkInput(select);
                    if (select == 0) {
                        break;
                    } else if (select == 1) {
                        continue;
                    } else {
                        cout << "Invalid input!" << endl;
                    }
                }
                break;
            }

            case DELETE: {
                cout<<"请输入要删除的学生id:"<<endl;
                checkInput(select);
                delStudent(select);
                break;
            }

            case UPDATE: {
                cout<<"请输入要更新的学生id:"<<endl;
                checkInput(select);
                updateStudent(select);
                break;
            }

            case FIND: {
                queryStudent();
                break;
            }

            case PRINT: {
                notifyStus();
                break;
            }

            case CLEAR: {
                clear();
                break;
            }

            case EXIT: {
                //写锁
                unique_lock<shared_mutex> lock(m_rwMutex);
                saveAllStus();
                clear(false);
                return;
            }

            default: {
                cout<<"Invalid input!"<<endl;
            };
        }
    }while (true);
}

template<typename T>
void ManageStu::checkInput(T &input) const {
    try {
        while(true) {
            if(cin>>input) break;
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            // 检查流状态
            if (cin.eof()) {
                throw CustomException("Unexpected EOF", CustomException::INVALID_INPUT);
            }
            if (cin.bad()) {
                throw CustomException("Stream corrupted", CustomException::INVALID_INPUT);
            }
            string typeName = typeid(T).name();
            cout << "Invalid input! Please enter a valid " << typeName << endl;
        }
    }catch (CustomException &e) {
        cout<<e.what()<<endl;
        ThreadPool *threadPool = ThreadPool::getInstance();
        threadPool->addTask([e](){FileUtils::logAccess(e.what(),false,UserContext::getCurrentUser());});
    }
}

void ManageStu::delInstance() {
    if(m_instance!= nullptr) {
        unique_lock<mutex> lock(m_mtx);
        if (m_instance!= nullptr) {
            delete m_instance;
            m_instance= nullptr;
        }
    }
}

ManageStu::~ManageStu()
{
    delInstance();
}

void ManageStu::printMenu() const{
    cout << "=========================" << endl;
    cout << "|" << setw(10) << left << "1.增加" << "|"
         << setw(10) << left << "2.删除" << "|" << endl;
    cout << "|" << setw(10) << left << "3.更新" << "|"
         << setw(10) << left << "4.查找" << "|" << endl;
    cout << "|" << setw(10) << left << "5.打印" << "|"
         << setw(10) << left << "6.清空" << "|" << endl;
    cout << "|" << setw(10) << left << "7.退出" << "|" << endl;
    cout << "========================" << endl;
}



